package main

import (
	"fmt"
	"log"
	"net"
	"netfly/comm"

	"strconv"

	toml "github.com/pelletier/go-toml"
	"github.com/tidwall/gjson"
)

var (
	strServer    string
	strDataPort  string
	strCtrlPort  string
	strToken     string
	strCloudPort string
	strLocalUrl  string
)

func ConnectDataServer() (cLocal net.Conn, cData net.Conn) {
	var err error
	cData, err = net.Dial("tcp", strServer+":"+strDataPort)
	if err != nil {
		log.Println("Data server connect error", err.Error())
		return
	}
	cLocal, err = net.Dial("tcp", strLocalUrl)
	if err != nil {
		log.Println("Local server connect error", err.Error())
		cData.Close()
		return
	}
	return
}
func main() {
	log.Println("netfly client start...")
	tConf, err := toml.LoadFile("./netflyc.toml")
	if err != nil {
		log.Println("Config File Load Error,", err.Error())
		return
	}
	strServer = tConf.Get("App.Server").(string)
	strDataPort = strconv.Itoa(int(tConf.Get("App.DataPort").(int64)))
	strCtrlPort = strconv.Itoa(int(tConf.Get("App.CtrlPort").(int64)))
	strToken = tConf.Get("App.Token").(string)

	strCloudPort = strconv.Itoa(int(tConf.Get("Netfly.Port").(int64)))
	strLocalUrl = tConf.Get("Netfly.Local").(string)

	// connect to ctrl server
	cCtrl, err := net.Dial("tcp", strServer+":"+strCtrlPort)
	if err != nil {
		log.Println("Connect to ctrl server error,", err.Error())
		return
	}
	defer cCtrl.Close()

	var sMsg string
	// login check token
	sMsg = fmt.Sprintf(`{"token":"%v","ask":"login"}`, strToken)
	strRet, _ := comm.SendCtrlMsgWait(sMsg, cCtrl, 0)
	log.Println(strRet)
	if gjson.Get(strRet, "answer").String() != "ok" {
		log.Println("Token check error, Exit!", strRet)
		return
	}
	// send open cloud port req
	sMsg = fmt.Sprintf(`{"token":"%v","ask":"open","port":"%v"}`, strToken, strCloudPort)
	strRet, _ = comm.SendCtrlMsgWait(sMsg, cCtrl, 0)
	log.Println(strRet)
	if gjson.Get(strRet, "answer").String() != "ok" {
		log.Println("Open cloud port error!", strCloudPort)
		return
	}
	// wait for pair msg and connect to data server
	var ok bool
	for {
		sMsg, ok = comm.WaitCtrlMsg(cCtrl, 0)
		if ok && len(sMsg) < 1 {
			continue
		}
		if !ok {
			log.Println("The Ctrl Connect failed! Logout!")
			break
		}
		log.Println("Ctrl Recv:", sMsg)
		strAsk := gjson.Get(sMsg, "ask").String()
		if strAsk == "pair" {
			uid := gjson.Get(sMsg, "uid").String()
			go pairDataConn(uid, strToken)
		}
	}

}

func pairDataConn(uid string, token string) {
	// connect to dataserver
	cLocal, cData := ConnectDataServer()

	strSend := fmt.Sprintf(`{"token":"%v","answer":"pair","uid":"%v"}`, token, uid)
	comm.SendCtrlMsg(strSend, cData)
	comm.MakeTunnel(cData, cLocal)
	// close
	cData.Close()
	cLocal.Close()
}
